home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d978.lha / NewEdit / NewEdit.artikel < prev    next >
Text File  |  1994-04-03  |  11KB  |  238 lines

  1.  
  2. NewEdit V1.6:
  3.  
  4.       Stringgadgets aufpoliert
  5.  
  6.  
  7. Stringgadgets gehören nicht gerade zu den
  8. Stärken von Intuition. Zwar hat sich
  9. mit Kickstart 2.0 einiges getan, daß aber
  10. noch mehr möglich ist, zeigt NewEdit 1.5.
  11. Copy und Paste zwischen Stringgadgets und
  12. dem Clipboard werden damit Wirklichkeit.
  13.  
  14.  
  15. Bereits in der AmigaPlus 8/92 wurde auf die Programmierung
  16. der Stringhooks unter Kickstart 2.0 eingegangen. Intuition
  17. bietet dafür zwei verschiedene Ansatzpunkte:
  18. Man kann lokale Stringhooks für jeweils ein einzelnes
  19. Stringgadget oder sogar eine neue globale Stringhook
  20. einhängen. Lokale Strinkhooks eignen sich dabei besonders
  21. für programmspezifische Sonderfunktionen. Denkbar wäre
  22. zum Beispiel eine Abfrage auf Tastenkürzel anderer Gadgets
  23. auch im Stringgadget, die anhand der gedrückten ALT-Taste
  24. erkannt werden.
  25.  
  26. Ganz andere Qualitäten bietet die globale Stringhook. Jene
  27. wird als Teil von Intuition vor allen lokalen Stringhooks
  28. aufgerufen und beinhaltet normalerweise die bekannten
  29. Editiermöglichkeiten. An dieser Stelle setzt NewEdit 1.6
  30. an.
  31.  
  32. NewEdit basiert auf dem gleichnamigen Programm von Oliver Wagner
  33. (AmigaPlus Diskette 9/92). Es kann von der Shell oder auch
  34. der Workbench gestartet werden und installiert dann
  35. seine eigene Stringhook vor die original Intuition-Hook. Mit
  36. CONTROL-C oder durch nochmaligen Aufruf von NewEdit wird die
  37. Hook wieder entfernt.
  38.  
  39. NewEdit V1.6 ist ein Commodity, daß sich bei der
  40. commodities.library anmeldet und von dort de-/aktiviert
  41. und entfernt werden kann. Dazu braucht man lediglich
  42. im Listview des ExChange Programms "NewEdit" anzuklicken
  43. und kann es dann wie gewohnt vorübergehend deaktivieren oder
  44. ganz entfernen.
  45.  
  46. Damit es dabei zu keinem verhängnisvollem Absturz kommt (die
  47. Edithook ist gerade aktiv, während NewEdit beendet wird...),
  48. wird eine Semaphore verwendet. Semaphores sind von Exec
  49. verwaltete "Zählvariablen", die einen exklusiven Zugriff auf
  50. kritische Resourcen ermöglichen. Das heißt, eigentlich handelt
  51. es ich hierbei um eine besondere Node-Struktur in einer
  52. verketteten Liste, jedoch lassen sie sich als Zählvariablen
  53. besser veranschaulichen:
  54.  
  55. Eine Semaphore ist mit einem positiven Wert - beim Amiga ist
  56. dies Eins - initialisiert. Jeweils ein Programm kann Zugriff auf
  57. eine Semaphore haben, nämlich dann, wenn diese einen Wert größer
  58. gleich 0 hat. Dies geschieht mittels ObtainSemaphore(), wobei der
  59. Semaphorewert um Eins erniedrigt wird.
  60.  
  61. Versuchen nun weitere Tasks auf dieselbe Semaphore zuzugreifen,
  62. so werden sie angehalten und in eine Warteschlange eingereiht.
  63. Erst wenn der aktuelle Besitzer der Semaphore mit der Funktion
  64. ReleaseSemaphore() den Zähler wieder erhöht, wird der nächste
  65. Task (der beim Zählerstand -1 angehalten wurde) aktiviert. Dies
  66. geschieht für den Programmierer völlig transparent. Man sollte
  67. daher immer daran denken, daß ein Aufruf von ObtainSemaphore()
  68. beliebig lange "dauern" kann.
  69.  
  70. Für NewEdit ist noch von Bedeutung, daß mit Kickstart 2.0
  71. ein gemeinsamer Zugriff auf eine Semaphore durch
  72. ObtainSemaphoreShared() möglich ist. Dies macht sich die
  73. Stringhook zu nutzen, die so theoretisch mehfach gleichzeitig
  74. benutzt werden kann. Dabei bleibt die Semaphore für einen
  75. exklusiven Zugriff jedoch gesperrt. Wenn NewEdit sich also
  76. beenden und damit die Stringhook wieder entfernen will,
  77. wird es solange bei ObtainSemaphore() aufgehalten, bis alle
  78. Edithooks ordnungsgemäß verlassen sind.
  79.  
  80.  
  81. Doch kommen wir zur eigentlichen Stringhook. Diese bietet
  82. nun eine Reihe von neuen Edierfunktionen, die das Arbeiten
  83. in Stringgadgets deutlich verbessern. So kann man nun mit
  84. ALT CURSOR LEFT auf den Anfang des vorherigen, beziehungsweise
  85. mit ALT CURSOR RIGHT zum Start des nächsten Wortes springen.
  86. Analog löscht ALT BACKSPACE das vorherige Wort und ALT DEL
  87. das nächste Wort. Die bereits vorhandenen SHIFT Funktionen,
  88. die sich jeweils bis an den Zeilenanfang/das Zeilenende auswirken,
  89. und AMIGA X zum Löschen der kompletten Zeile, bleiben erhalten.
  90.  
  91. Falls mehrere Stringgadgets in einem Fenster vorhanden sind,
  92. so kann mit der rechten Alttaste und CURSOR UP/DOWN zwischen
  93. diesen frei gewechselt werden. Voraussetzung ist, daß der
  94. Programmierer für seine Stringgadgets die TAB-Wechselfunktion
  95. freigegeben hatte (das heißt, in der Gadgetstruktur ist
  96. GFLG_TABCYCLE gesetzt). Die Kombination der Cursortasten mit
  97. der rechten Alttaste wurde deshalb gewählt, um nicht in
  98. Konflikt mit verschiedenen Filerequestern (wie zum Beispiel
  99. dem MFR) zu kommen, die für ihre Dateiauswahl ebenfalls
  100. die Cursortasten verwenden. Außerdem kann man mit ESCAPE ein
  101. Stringgadget verlassen, als hätte man RETURN gedrückt.
  102.  
  103. Zum Schluß noch das Bonbon unter den neuen Editierfunktionen:
  104. Wie oft hat man sich nicht schon darüber geärgert, wenn man
  105. in seinem Editor nach einer Textstelle suchen will, diese
  106. auch gerade markiert hatte und doch muß man nun in den
  107. Suchrequester den ganzen Text von Hand erneut abtippen.
  108. Dabei gibt es doch das Clipboard, das heute zum Glück
  109. von den meisten Editoren für Blockoperationen genutzt wird.
  110. Auch aus den neuen Consolen kann man markierten Text mit
  111. AMIGA-C ins Clipboard kopieren.
  112.  
  113. NewEdit 1.6 unterstützt ebenfalls das Clipboard! Wie
  114. gewohnt kann man nun mit AMIGA C den ganzen Inhalt eines
  115. Stringgadgets in das Clipboard kopieren und mit AMIGA V
  116. Text aus dem Clipboard an der Cursurposition einfügen.
  117. Wenn man sich daran einmal gewöhnt hat, möchte man diese
  118. Funktionen nicht mehr missen. Bleibt die Frage, warum
  119. Commodore hier so inkonsequent ist und bisher nicht
  120. selbst diese Fähigkeiten implementiert hat?
  121.  
  122. Der programmtechnische Umgang mit dem Clipboard gestaltet
  123. sich etwas schwierig. Das Clipboard enthält immer IFF-Daten,
  124. wobei nur das Format FTXT für Clipboardtext von NewEdit
  125. unterstützt wird (ILBM Daten würden einem Stringgadget
  126. auch nicht viel Freude bereiten). Um die IFF-Daten lesen
  127. und schreiben zu können, verwendet NewEdit die Commodores
  128. iffparse.library.
  129.  
  130. Die IffParse Library zählt leider zu den unübersichtlichsten
  131. Libraries unter 2.0. Um den Umgang damit zu erleichtern,
  132. finden sich in clipboard.c vier Funktionen, mit denen
  133. normale Strings in das Clipboard Unit 0 geschrieben und davon
  134. gelesen werden können. Dahinter verbirgt sich der Kampf
  135. mit den Elementen: Zuerst muß die iffparse.library
  136. geöffnet, ein sogenannter IFFHandle angelegt und für das
  137. ClipBoard initialisiert werden. Die iffparse.library
  138. kann nämlich sowohl auf DOS-Filehandle, als auch speziell
  139. auf das clipboard.device zugreifen. Dies alles erledigt
  140. init_iffparse(). Pendant dazu ist close_iffparse(), daß am
  141. Ende wieder alles freigibt und schließt.
  142.  
  143. Mit write_clip() kann nun Text in das Clipboard geschrieben
  144. werden. Dazu muß eine korrekte Iff-FTXT-Struktur erzeugt
  145. werden. Iff-Daten bestehen immer aus einem Kopf und einem
  146. Rumpf, wobei diese sogennanten Chunks wiederum beliebig
  147. geschachtelt sein können. Analog ist die Logik der
  148. iffparse.library, nämlich rekursiv. Erzeugt werden die Daten
  149. auf einem  Stapel - zuerst werden der FTXT-Kopf, dann der
  150. CHRS-Daten-Chunk (der auch den eigentlichen ASCII-Text
  151. enthält) mit PushChunk() darauf abgelegt. Dann wird die
  152. so erzeugte IFF-Struktur weggespeichert und der Stapel
  153. wieder gelehrt (zu jedem PushChunk() ein PopChunk() ).
  154.  
  155. read_clip() liest entsprechend aus dem Clipboard heraus.
  156. Erschwehrend kommt nun hinzu, daß im Clipboard beliebige
  157. IFF-Formate liegen können und nur ein FTXT-Chunk
  158. eingelesen werden soll. Die iffparse.library bietet hierzu
  159. die Funktion StopChunk(), mit der ihr mitgeteilt wird,
  160. welche Daten gesucht werden. Danach wird mit ParseIFF()
  161. über einem IFFHandle (bei NewEdit auf das Clipboard
  162. initialisiert) eine IFF Struktur solange durchsucht,
  163. bis der gewünschte Datenchunk erreicht ist. Wie gesagt,
  164. IFF-Daten können beliebig verschachtelt sein.
  165.  
  166. Wenn nun ParseIFF() zurückkehrt, so ist entweder das
  167. Ende der IFF-Daten oder der gesuchte Datenchunk
  168. erreicht. Welches Format nun im aktuellen Chunk vorliegt
  169. erfährt man mittels CurrentChunk(), das eine sogenannte
  170. ContextNode füllt. Hierin kann man nun entgültig auf
  171. das gesuchte Format testen und gegebenenfalls mit
  172. ReadChunkBytes() die eigentlichen ASCII-Zeichen
  173. einlesen. Wie man liest, habe ich nicht zu viel
  174. versprochen - die iffparse.library ist kompliziert.
  175.  
  176. Um zu ursprünglichen Stringhook zurückzukehren noch
  177. zwei Hinweise: Die Stringhook von NewEdit ruft immer
  178. noch Intuition's ursprüngliche Edithook auf, wodurch
  179. alle üblichen Editierfunktionen erhalten bleiben und
  180. vorallem das Stringgadget immer aktualisiert wird.
  181. Allerdings muß mitunter verhindert werden, daß dort
  182. die bereits interpretierten Tasten erneut ausgewertet
  183. werden. Sonst würde zum Beispiel nach AMIGA-V zusätzlich
  184. noch ein V im Stringgadget auftauchen. Das Problem
  185. ist etwas unsauber gelöst: Der Inputeventcode der
  186. aktuellen Taste wird auf den unbenutzten Wert 0
  187. verdreht, wodurch die weiteren Editierhooks untätig
  188. bleiben. Außerdem vermerkt NewEdit in dem Feld
  189. EditOp der übergebenen SGWork-Struktur die Operation
  190. EO_BIGCHANGE, falls Text eingefügt oder Worte gelöscht
  191. wurden. Somit können spätere Edithooks auf diesen
  192. Wert achten.
  193.  
  194.  
  195.  
  196. Datenstrukturen:
  197.  
  198. Die SignalSemaphore-Struktur:
  199. struct SignalSemaphore {
  200.     struct  Node ss_Link;                    /* Verkettung innerhalb von SysBase->SemList, */
  201.                                              /* enthält vorallem Priorität und Name        */
  202.     WORD    ss_NestCount;                    /* der eigentliche Zähler                     */
  203.     struct  MinList ss_WaitQueue;            /* Warteschlange für anfragende Tasks         */
  204.     struct  SemaphoreRequest ss_MultipleLink;
  205.     struct  Task *ss_Owner;                  /* Adresse des momentanen Besitzer-Tasks      */
  206.     WORD    ss_QueueCount;                   /* Größe der Warteschlange                    */
  207. };
  208.  
  209.  
  210. Die IFFHandle-Struktur:
  211. struct IFFHandle {
  212.    ULONG iff_Stream;
  213.    ULONG iff_Flags;
  214.    LONG  iff_Depth;  /*  Tiefe des Context-Stacks.  */
  215.    /*  Dahinter noch weitere private Felder...  */
  216. };
  217.  
  218.  
  219. Die ContextNode Struktur:
  220. struct ContextNode {
  221.    struct MinNode cn_Node;
  222.    LONG     cn_ID;   /*  Chunk-ID, beu uns ID_CHRS (vgl. unten)   */
  223.    LONG     cn_Type; /*  Datentyp, für uns nur ID_FTXT            */
  224.    LONG     cn_Size; /*  Größe des zugehörigen Chunks             */
  225.    LONG     cn_Scan; /*  Anzahl Zeichen bisher geschrieben/-lesen */
  226.    /*  Dahinter noch weitere private Felder...  */
  227. };
  228. /* universelle IFF ID's */
  229. #define  MAKE_ID(a,b,c,d)  \
  230.    ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))
  231. #define  ID_FORM   MAKE_ID('F','O','R','M')
  232. #define  ID_LIST   MAKE_ID('L','I','S','T')
  233. #define  ID_CAT    MAKE_ID('C','A','T',' ')
  234. #define  ID_PROP   MAKE_ID('P','R','O','P')
  235. #define  ID_NULL   MAKE_ID(' ',' ',' ',' ')
  236. #define  ID_FTXT   MAKE_ID('F','T','X','T')
  237. #define  ID_CHRS   MAKE_ID('C','H','R','S')
  238.